﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace Level_Editor
{
    public partial class Form1 : Form
    {
        private OpenFileDialog openFileDialog;
        private SaveFileDialog saveFileDialog;
        private Image background;
        private bool saved;
        private String currFile;
        private bool waypointing = false;
        private List<Instance> currentWaypoints = new List<Instance>();
        private Instance potential = null;
        private int previousActor = -1;
        private String levelBrief = "";

        public Form1()
        {
            InitializeComponent();

            openFileDialog = new OpenFileDialog();
            openFileDialog.RestoreDirectory = false;
            openFileDialog.InitialDirectory = Application.StartupPath;

            saveFileDialog = new SaveFileDialog();
            saveFileDialog.RestoreDirectory = false;
            saveFileDialog.InitialDirectory = Application.StartupPath;
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            lblBackground.Left = pictureBox.Width + 18;
            txtBackground.Left = pictureBox.Width + 92;
            txtBackground.Width = this.Width - pictureBox.Width - 201;
            btnBrowse.Left = this.Width - 103;

            chkTime.Left = pictureBox.Width + 24;
            txtTime.Left = pictureBox.Width + 199;
            txtTime.Width = this.Width - pictureBox.Width - 227;

            grpActors.Left = pictureBox.Width + 18;
            grpActors.Width = this.Width - pictureBox.Width - 46;
            listActors.Width = grpActors.Width - 12;

            grpInstances.Left = pictureBox.Width + 18;
            grpInstances.Width = this.Width - pictureBox.Width - 46;
            listInstances.Width = grpInstances.Width - 12;
            txtX.Width = Convert.ToInt32(Math.Round(grpInstances.Width * 0.15));
            txtY.Width = txtX.Width;
            txtAngle.Width = txtX.Width;
            txtSpawn.Width = txtX.Width;
            grpNeighbours.Left = txtX.Width + 61;
            grpNeighbours.Width = grpInstances.Width - txtX.Width - 68;
            listNeighbours.Width = grpNeighbours.Width - 12;

            grpWin.Left = pictureBox.Width + 18;
            grpWin.Width = (this.Width - pictureBox.Width - 49) / 2;
            grpLose.Width = grpWin.Width;
            grpLose.Left = this.Width - grpLose.Width - 28;
            txtWWolf.Width = grpWin.Width - 98;
            txtLSheep.Width = grpLose.Width - 98;
            
            int excess = this.Height - 557;

            grpActors.Height = 112 + Convert.ToInt32(Math.Round(excess * 0.3166));
            listActors.Height = 82 + Convert.ToInt32(Math.Round(excess * 0.3166));

            grpInstances.Top = 199 + Convert.ToInt32(Math.Round(excess * 0.3166));
            grpInstances.Height = 236 + Convert.ToInt32(Math.Round(excess * 0.6834));
            listInstances.Height = 108 + Convert.ToInt32(Math.Round(excess * 0.417));
            lblX.Top = 136 + Convert.ToInt32(Math.Round(excess * 0.417));
            txtX.Top = 133 + Convert.ToInt32(Math.Round(excess * 0.417));
            lblY.Top = 161 + Convert.ToInt32(Math.Round(excess * 0.417));
            txtY.Top = 158 + Convert.ToInt32(Math.Round(excess * 0.417));
            lblAngle.Top = 186 + Convert.ToInt32(Math.Round(excess * 0.417));
            txtAngle.Top = 183 + Convert.ToInt32(Math.Round(excess * 0.417));
            lblSpawn.Top = 211 + Convert.ToInt32(Math.Round(excess * 0.417));
            txtSpawn.Top = 208 + Convert.ToInt32(Math.Round(excess * 0.417));
            grpNeighbours.Top = 133 + Convert.ToInt32(Math.Round(excess * 0.417));
            grpNeighbours.Height = 95 + Convert.ToInt32(Math.Round(excess * 0.2664));
            listNeighbours.Height = 69 + Convert.ToInt32(Math.Round(excess * 0.2664));

            grpWin.Top = 441 + excess;
            grpLose.Top = 441 + excess;
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            Stream myStream;

            openFileDialog.Filter = "PNG files (*.png)|*.png|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                if ((myStream = openFileDialog.OpenFile()) != null)
                {
                    txtBackground.Text = openFileDialog.FileName;
                    background = resize(Bitmap.FromFile(txtBackground.Text));
                    updateImage();
                    myStream.Close();
                }
            }

            openFileDialog.Reset();

            saved = false;
        }

        private Image resize(Image b)
        {
            Bitmap result = new Bitmap(320, 480);
            using (Graphics g = Graphics.FromImage((Image)result))
                g.DrawImage(b, 0, 0, 320, 480);
            return result;
        }

        private void updateImage()
        {
            pictureBox.Image = createImage();
        }

        private void chkTime_CheckedChanged(object sender, EventArgs e)
        {
            txtTime.Enabled = chkTime.Checked;
            chkWTime.Enabled = chkTime.Checked;
            chkLTime.Enabled = chkTime.Checked;
            chkWTime.Checked = false;
            chkLTime.Checked = false;

            saved = false;
        }

        private void Form1_ResizeEnd(object sender, EventArgs e)
        {
            if (this.Width < pictureBox.Width + 300)
                this.Width = pictureBox.Width + 300;
        }

        private void loadNewActorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialog.Filter = "Actor files (*.act)|*.act|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                Actor newActor = Actor.loadActor(openFileDialog.FileName);
                if (newActor != null)
                {
                    listActors.Items.Add(newActor);
                    saved = false;
                }
            }

            openFileDialog.Reset();
        }

        private void unloadSelectedActorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listActors.SelectedItem == null)
                return;

            if (((Actor)listActors.SelectedItem).instances == 0)
                listActors.Items.Remove(listActors.SelectedItem);
            else
            {
                DialogResult myResult = MessageBox.Show("There are active instances of this Actor. If you unload this Actor, they will also be removed. Do you wish to continue with unloading?", "Level Editor", MessageBoxButtons.YesNoCancel);

                if (myResult == DialogResult.Yes)
                {
                    for (int i = 0; i < listInstances.Items.Count; i++)
                        if (((Instance) listInstances.Items[i]).actor == listActors.SelectedItem)
                            listInstances.Items.RemoveAt(i--);
                    
                    listActors.Items.Remove(listActors.SelectedItem);
                }
                else if (myResult == DialogResult.Cancel)
                {
                    return;
                }
            }

            saved = false;
        }

        private void addToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Instance newInstance;

            if (comboActors.Text == "Waypoint")
                newInstance = new Instance(null);
            else
                newInstance = new Instance((Actor) comboActors.SelectedItem);

            if (newInstance != null)
            {
                listInstances.Items.Add(newInstance);
                listInstances.SelectedItem = newInstance;
                saved = false;
                updateImage();
            }
        }

        private void listInstances_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listActors.SelectedItem != null && listInstances.SelectedItem == null)
                pictureBox.Cursor = new Cursor(new Bitmap(((Actor)listActors.SelectedItem).actors[0]).GetHicon());
            else
                pictureBox.Cursor = Cursors.Default;
            
            bool _saved = saved;

            Instance currItem = (Instance)listInstances.SelectedItem;

            if (currItem == null)
            {
                lblX.Enabled = false;
                lblY.Enabled = false;
                lblAngle.Enabled = false;
                lblSpawn.Enabled = false;
                txtX.Enabled = false;
                txtY.Enabled = false;
                txtAngle.Enabled = false;
                txtSpawn.Enabled = false; 
                grpNeighbours.Enabled = false;
                listNeighbours.Enabled = false;

                txtX.Text = "";
                txtY.Text = "";
                txtAngle.Text = "";
                txtSpawn.Text = "";
                listNeighbours.Items.Clear();

                return;
            }

            lblX.Enabled = true;
            lblY.Enabled = true;
            txtX.Enabled = true;
            txtY.Enabled = true;

            txtX.Text = currItem.x.ToString();
            txtY.Text = currItem.y.ToString();

            if (!currItem.isWaypoint())
            {
                lblAngle.Enabled = true;
                txtAngle.Enabled = true;
                grpNeighbours.Enabled = false;
                listNeighbours.Items.Clear();
                listNeighbours.Enabled = false;

                txtAngle.Text = currItem.angle.ToString();

                if (currItem.actor.type == 0)
                {
                    lblSpawn.Enabled = true;
                    txtSpawn.Enabled = true;

                    txtSpawn.Text = currItem.spawn.ToString();
                }
                else
                {
                    lblSpawn.Enabled = false;
                    txtSpawn.Enabled = false;

                    txtSpawn.Text = "";
                }
            }
            else
            {
                lblSpawn.Enabled = false;
                txtSpawn.Enabled = false;
                txtSpawn.Text = "";

                lblAngle.Enabled = false;
                txtAngle.Enabled = false;
                txtAngle.Text = "";

                grpNeighbours.Enabled = true;
                listNeighbours.Enabled = true;
                listNeighbours.Items.Clear();

                foreach (Instance waypoint in currItem.neighbours)
                    listNeighbours.Items.Add(waypoint);
            }

            saved = _saved;
        }

        private void txtX_TextChanged(object sender, EventArgs e)
        {
            Instance currItem = (Instance)listInstances.SelectedItem;

            if (currItem == null)
                return;

            try
            {
                currItem.x = Convert.ToInt32(txtX.Text);
            }
            catch (Exception)
            {
            }

            saved = false;
            updateImage();
        }

        private void txtY_TextChanged(object sender, EventArgs e)
        {
            Instance currItem = (Instance)listInstances.SelectedItem;

            if (currItem == null)
                return;

            try
            {
                currItem.y = Convert.ToInt32(txtY.Text);
            }
            catch (Exception)
            {
            }

            saved = false;
            updateImage();
        }

        private void txtAngle_TextChanged(object sender, EventArgs e)
        {
            Instance currItem = (Instance)listInstances.SelectedItem;

            if (currItem == null)
                return;

            try
            {
                currItem.angle = Convert.ToInt32(txtAngle.Text);
            }
            catch (Exception)
            {
            }

            saved = false;
            updateImage();
        }

        private void txtSpawn_TextChanged(object sender, EventArgs e)
        {
            Instance currItem = (Instance)listInstances.SelectedItem;

            if (currItem == null)
                return;

            try
            {
                currItem.spawn = Convert.ToInt32(txtSpawn.Text);
            }
            catch (Exception)
            {
            }

            saved = false;
            updateImage();
        }

        private void deleteSelectedInstanceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listInstances.SelectedItem == null)
                return;

            if (((Instance)listInstances.SelectedItem).actor == null)
            {
                foreach (Instance neighbour in ((Instance)listInstances.SelectedItem).neighbours)
                    neighbour.neighbours.Remove((Instance)listInstances.SelectedItem);
                Instance.waypoints--;
            }
            else
            {
                ((Instance)listInstances.SelectedItem).actor.instances--;
            }
            
            listInstances.Items.Remove(listInstances.SelectedItem);

            saved = false;
            updateImage();
        }

        private void deleteSelectedNeighbourToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listNeighbours.SelectedItem == null)
                return;

            ((Instance)listNeighbours.SelectedItem).neighbours.Remove((Instance)listInstances.SelectedItem);
            ((Instance)listInstances.SelectedItem).neighbours.Remove((Instance)listNeighbours.SelectedItem);
            listNeighbours.Items.Remove(listNeighbours.SelectedItem);

            saved = false;
            updateImage();
        }

        private void addNeighbourToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            Instance selectedItem = (Instance)listInstances.SelectedItem;

            comboNeighbours.Items.Clear();

            foreach (Instance waypoint in listInstances.Items)
                if (waypoint.actor == null && waypoint != selectedItem)
                    comboNeighbours.Items.Add(waypoint);

            foreach (Instance waypoint in listNeighbours.Items)
                comboNeighbours.Items.Remove(waypoint);

            comboNeighbours.SelectedIndex = 0;
        }

        private void addNewInstanceToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            comboActors.Items.Clear();
            comboActors.Items.Add("Waypoint");

            foreach (Actor actor in listActors.Items)
                comboActors.Items.Add(actor);

            if (listActors.SelectedItem != null)
                comboActors.SelectedItem = listActors.SelectedItem;
            else
                comboActors.SelectedIndex = 0;
        }

        private void addToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (listInstances.SelectedItem == null || comboNeighbours.SelectedItem == null)
                return;
            
            ((Instance) listInstances.SelectedItem).neighbours.Add((Instance) comboNeighbours.SelectedItem);
            ((Instance) comboNeighbours.SelectedItem).neighbours.Add((Instance) listInstances.SelectedItem);
            listNeighbours.Items.Add((Instance)comboNeighbours.SelectedItem);

            saved = false;
            updateImage();
        }

        private void chkLSheep_CheckedChanged(object sender, EventArgs e)
        {
            if (chkLSheep.Checked)
            {
                txtLSheep.Enabled = true;
            }
            else
            {
                txtLSheep.Enabled = false;
                txtLSheep.Text = "";
            }
        }

        private void chkWWolf_CheckedChanged(object sender, EventArgs e)
        {
            if (chkWWolf.Checked)
            {
                txtWWolf.Enabled = true;
            }
            else
            {
                txtWWolf.Enabled = false;
                txtWWolf.Text = "";
            }

            saved = false;
        }

        private void chkWTime_CheckedChanged(object sender, EventArgs e)
        {
            chkLTime.Enabled = !chkWTime.Checked && chkTime.Checked;
            saved = false;
        }

        private void chkLTime_CheckedChanged(object sender, EventArgs e)
        {
            chkWTime.Enabled = !chkLTime.Checked && chkTime.Checked;
            saved = false;
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!saved && currFile != null)
                saveFile(currFile);
            else if (!saved)
                saveAsToolStripMenuItem_Click(sender, e);
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog.Filter = "Level files (*.lvl)|*.lvl|All files (*.*)|*.*";
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.FileName = Path.GetFileNameWithoutExtension(txtBackground.Text) + ".lvl";

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                saveFile(saveFileDialog.FileName);
            }

            saveFileDialog.Reset();
        }

        private void saveFile(string file)
        {
            try
            {
                StringBuilder output = new StringBuilder();
                StreamWriter myStream;
                                
                if ((myStream = new StreamWriter(file)) != null)
                {
                    output.AppendLine(@"Textures/" + Path.GetFileNameWithoutExtension(txtBackground.Text) + ".png");
                    
                    if (chkTime.Checked)
                        output.AppendLine(txtTime.Text);
                    else
                        output.AppendLine("0");
                    
                    if (chkWWolf.Checked)
                        output.AppendLine(txtWWolf.Text);
                    else
                        output.AppendLine("-1");
                    
                    if (chkWTime.Checked)
                        output.AppendLine("1");
                    else
                        output.AppendLine("0");
                    
                    if (chkLSheep.Checked)
                        output.AppendLine(txtLSheep.Text);
                    else
                        output.AppendLine("-1");
                    
                    if (chkLTime.Checked)
                        output.AppendLine("1");
                    else
                        output.AppendLine("0");
                    
                    output.AppendLine(listActors.Items.Count.ToString());

                    int i = 4;

                    while (true)
                    {
                        foreach (Actor actor in listActors.Items)
                        {
                            if (actor.type == i)
                            {
                                output.AppendLine(@"Actors/" + Path.GetFileName(actor.file));
                                output.AppendLine(actor.instances.ToString());

                                foreach (Instance instance in listInstances.Items)
                                {
                                    if (instance.actor == actor)
                                    {
                                        output.AppendLine(instance.x.ToString());
                                        output.AppendLine(instance.y.ToString());
                                        output.AppendLine(instance.angle.ToString());

                                        if (actor.type == 0)
                                            output.AppendLine(instance.spawn.ToString());
                                    }
                                }
                            }
                        }

                        if (i == 1) break;
                        if (i == 0) i = 1;
                        if (i == 2) i = 0;
                        if (i == 3) i = 2;
                        if (i == 4) i = 3;
                    }

                    int waypointIndex = 0;

                    foreach (Instance waypoint in listInstances.Items)
                    {
                        if (waypoint.isWaypoint())
                            waypoint.actualIndex = waypointIndex++;
                    }
                    
                    output.AppendLine(waypointIndex.ToString());
                    
                    foreach (Instance waypoint in listInstances.Items)
                    {
                        if (waypoint.isWaypoint())
                        {
                            output.AppendLine(waypoint.x.ToString());
                            output.AppendLine(waypoint.y.ToString());

                            output.AppendLine(waypoint.neighbours.Count.ToString());

                            foreach (Instance neighbour in waypoint.neighbours)
                            {
                                output.AppendLine(neighbour.actualIndex.ToString());
                            }
                        }
                    }

                    output.AppendLine(levelBrief.Replace("\\n", "\n"));

                    output.Replace("\r", "");
                    myStream.Write(output.ToString());
                    myStream.Close();

                    saved = true;
                    currFile = file;

                    this.Text = "Level Editor - " + Path.GetFileNameWithoutExtension(currFile) + ".lvl";
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Unable to save " + file + ". Error: " + e.Message + " - " + e.TargetSite, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void txtTime_TextChanged(object sender, EventArgs e)
        {
            saved = false;
        }

        private void txtWWolf_TextChanged(object sender, EventArgs e)
        {
            saved = false;
        }

        private void txtLSheep_TextChanged(object sender, EventArgs e)
        {
            saved = false;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!saved)
            {
                DialogResult myResult = MessageBox.Show("Save changes to current level?", "Level Editor", MessageBoxButtons.YesNoCancel);

                if (myResult == DialogResult.Yes)
                {
                    saveToolStripMenuItem_Click(this, null);
                }
                else if (myResult == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            openFile(Application.StartupPath + @"\Levels\example.lvl");
        }

        private void newLevelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!saved)
            {
                DialogResult myResult = MessageBox.Show("Save changes to current level?", "Level Editor", MessageBoxButtons.YesNoCancel);

                if (myResult == DialogResult.Yes)
                {
                    saveToolStripMenuItem_Click(this, null);
                }
                else if (myResult == DialogResult.Cancel)
                {
                    return;
                }
            }

            clearAll();

            saved = true;
            currFile = null;
        }

        private void clearAll()
        {
            background = null;
            Instance.waypoints = 0;
            Instance.waypointIndices = 0;

            txtBackground.Text = "";
            chkTime.Checked = false;
            txtTime.Text = "";
            txtTime.Enabled = false;

            listActors.Items.Clear();
            listInstances.Items.Clear();
            lblX.Enabled = false;
            txtX.Text = "";
            txtX.Enabled = false;
            lblY.Enabled = false;
            txtY.Text = "";
            txtY.Enabled = false;
            lblAngle.Enabled = false;
            txtAngle.Text = "";
            txtAngle.Enabled = false;
            lblSpawn.Enabled = false;
            txtSpawn.Text = "";
            txtSpawn.Enabled = false;
            grpNeighbours.Enabled = false;
            listNeighbours.Items.Clear();
            listNeighbours.Enabled = false;

            chkWWolf.Checked = false;
            txtWWolf.Text = "";
            txtWWolf.Enabled = false;
            chkWTime.Checked = false;
            chkWTime.Enabled = false;

            chkLSheep.Checked = false;
            txtLSheep.Text = "";
            txtLSheep.Enabled = false;
            chkLTime.Checked = false;
            chkLTime.Enabled = false;

            pictureBox.Image = null;

            this.Text = "Level Editor";
        }

        private void openLevelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!saved)
            {
                DialogResult myResult = MessageBox.Show("Save changes to current level?", "Level Editor", MessageBoxButtons.YesNoCancel);

                if (myResult == DialogResult.Yes)
                {
                    saveToolStripMenuItem_Click(sender, e);
                }
                else if (myResult == DialogResult.Cancel)
                {
                    return;
                }
            }

            openFileDialog.Filter = "Level files (*.lvl)|*.lvl|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                openFile(openFileDialog.FileName);
            }

            openFileDialog.Reset();
        }

        private void openFile(string file)
        {
            StreamReader myStream;

            try
            {

                if ((myStream = new StreamReader(file)) != null)
                {
                    try
                    {
                        clearAll();

                        String line;

                        // Background image
                        line = myStream.ReadLine();
                        if (line.Length > 4)
                        {
                            txtBackground.Text = Path.GetDirectoryName(file).Replace("Levels", "") + line;
                            background = resize(Bitmap.FromFile(txtBackground.Text));
                            updateImage();
                        }

                        // Countdown timer
                        line = myStream.ReadLine();
                        if (Convert.ToInt32(line) > 0)
                        {
                            chkTime.Checked = true;
                            txtTime.Enabled = true;
                            txtTime.Text = line;
                        }
                        
                        // Winning condition
                        line = myStream.ReadLine();
                        if (Convert.ToInt32(line) != -1)
                        {
                            chkWWolf.Checked = true;
                            txtWWolf.Enabled = true;
                            txtWWolf.Text = line;
                        }

                        line = myStream.ReadLine();
                        if (Convert.ToInt32(line) == 1)
                        {
                            chkWTime.Checked = true;
                        }

                        // Losing condition
                        line = myStream.ReadLine();
                        if (Convert.ToInt32(line) != -1)
                        {
                            chkLSheep.Checked = true;
                            txtLSheep.Enabled = true;
                            txtLSheep.Text = line;
                        }

                        line = myStream.ReadLine();
                        if (Convert.ToInt32(line) == 1)
                        {
                            chkLTime.Checked = true;
                        }

                        // Actors
                        int actors = Convert.ToInt32(myStream.ReadLine());

                        for (int i = 0; i < actors; i++)
                        {
                            Actor newActor = Actor.loadActor(Path.GetDirectoryName(file).Replace("Levels", "") + myStream.ReadLine());
                            listActors.Items.Add(newActor);

                            // Instances
                            int instances = Convert.ToInt32(myStream.ReadLine());

                            for (int j = 0; j < instances; j++)
                            {
                                Instance newInstance = new Instance(newActor);
                                listInstances.Items.Add(newInstance);

                                newInstance.x = Convert.ToInt32(myStream.ReadLine());
                                newInstance.y = Convert.ToInt32(myStream.ReadLine());
                                newInstance.angle = Convert.ToInt32(myStream.ReadLine());

                                if (newActor.type == 0)
                                    newInstance.spawn = Convert.ToInt32(myStream.ReadLine());
                            }
                        }

                        // Waypoints
                        int waypoints = Convert.ToInt32(myStream.ReadLine());
                        List<Instance> listWaypoints = new List<Instance>();

                        for (int i = 0; i < waypoints; i++)
                        {
                            listWaypoints.Add(new Instance(null));
                        }

                        for (int i = 0; i < waypoints; i++)
                        {
                            listWaypoints[i].x = Convert.ToInt32(myStream.ReadLine());
                            listWaypoints[i].y = Convert.ToInt32(myStream.ReadLine());

                            int neighbours = Convert.ToInt32(myStream.ReadLine());

                            for (int j = 0; j < neighbours; j++)
                            {
                                listWaypoints[i].neighbours.Add(listWaypoints[Convert.ToInt32(myStream.ReadLine())]);
                            }
                        }

                        foreach (Instance waypoint in listWaypoints)
                            listInstances.Items.Add(waypoint);

                        levelBrief = myStream.ReadToEnd().Replace("\n", "\\n");
                        
                        if (levelBrief.Length < 2)
                            levelBrief = "";
                        else
                            levelBrief = levelBrief.Substring(0, levelBrief.Length - 2);

                        saved = true;
                        currFile = file;
                        updateImage();
                        autoResizeToolStripMenuItem_Click(this, null);
                        
                        this.Text = "Level Editor - " + Path.GetFileNameWithoutExtension(currFile) + ".lvl";
                    }
                    catch (Exception e)
                    {
                        clearAll();
                        saved = true;
                        currFile = null;
                        MessageBox.Show("Unable to open " + file + ". Error: " + e.Message + " - " + e.TargetSite + " - " + e.TargetSite, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
            catch (Exception e)
            {
                clearAll();
                saved = true;
                currFile = null;
                MessageBox.Show("Unable to open " + file + ". " + e.Message + " - " + e.TargetSite, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private Image createImage()
        {
            try
            {
                Instance selectedItem = (Instance) listInstances.SelectedItem;
                Pen selected = new Pen(Color.Red, 2);
                selected.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

                if (selectedItem == null && potential != null)
                {
                    selectedItem = potential;
                    selected = new Pen(Color.Pink, 2);
                }

                Image canvas = new Bitmap(background);
                Graphics overlay = Graphics.FromImage(canvas);
                Brush myBrush;

                // Draw waypoints
                myBrush = new SolidBrush(Color.Black);
                foreach (Instance waypoint in listInstances.Items)
                {
                    if (waypoint.isWaypoint())
                    {
                        overlay.FillEllipse(myBrush, waypoint.x - 3, background.Height - 1 - waypoint.y - 3, 7, 7);

                        foreach (Instance neighbour in waypoint.neighbours)
                        {
                            overlay.DrawLine(new Pen(Color.Black), waypoint.x, background.Height - 1 - waypoint.y, neighbour.x, background.Height - 1 - neighbour.y);
                        }
                    }
                }

                // Other instances
                foreach (Instance instance in listInstances.Items)
                {
                    if (!instance.isWaypoint())
                        overlay.DrawImage(instance.actor.actors[instance.angle], instance.x - instance.actor.actors[0].Width / 2, background.Height - 1 - instance.y - instance.actor.actors[0].Height / 2);
                }

                // Selected/Potential item
                if (selectedItem != null)
                {
                    if (((Instance)selectedItem).isWaypoint())
                        overlay.DrawEllipse(selected, selectedItem.x - 9, background.Height - 1 - selectedItem.y - 9, 19, 19);
                    else
                        overlay.DrawEllipse(selected, (float)(selectedItem.x - selectedItem.actor.actors[0].Width / 1.8), (float)(background.Height - 1 - selectedItem.y - selectedItem.actor.actors[0].Height / 1.8), (float)(selectedItem.actor.actors[0].Width / .9), (float)(selectedItem.actor.actors[0].Height / .9));
                }

                return canvas;
            }
            catch (Exception)
            {
                return pictureBox.Image;
            }
         
        }

        private void autoResizeToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void pictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (listInstances.SelectedItem != null)
                    listInstances.SelectedIndex = -1;
                else if (listActors.SelectedItem != null)
                    listActors.SelectedIndex = -1;

                updateImage();
            } 
            else if (!waypointing && listInstances.SelectedItem != null)
            {
                txtX.Text = e.X.ToString();
                txtY.Text = (background.Height - 1 - e.Y).ToString();
            }
            else if (waypointing)
            {
                if (background == null)
                    return;

                Instance newWaypoint = new Instance(null);

                newWaypoint.x = e.X;
                newWaypoint.y = (background.Height - 1 - e.Y);

                if (newWaypoint != null)
                {
                    listInstances.Items.Add(newWaypoint);
                    foreach (Instance waypoint in currentWaypoints)
                    {
                        waypoint.neighbours.Add(newWaypoint);
                        newWaypoint.neighbours.Add(waypoint);
                    }
                    currentWaypoints.Add(newWaypoint);
                    saved = false;
                    updateImage();
                }
            }
            else if (listInstances.SelectedItem == null && potential != null)
            {
                listInstances.SelectedItem = potential;
                updateImage();
            }
        }

        private void lblAngle_MouseClick(object sender, MouseEventArgs e)
        {
            try
            {
                if (e.Button == MouseButtons.Right)
                    txtAngle.Text = ((Convert.ToInt32(txtAngle.Text) + 1) % 12).ToString();
                else
                    txtAngle.Text = ((Convert.ToInt32(txtAngle.Text) + 11) % 12).ToString();
            }
            catch (Exception)
            {
            }
        }

        private void listActors_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (previousActor == listActors.SelectedIndex)
            {
                previousActor = -1;
                listActors.SelectedIndex = -1;
            }
            else
            {
                previousActor = listActors.SelectedIndex;
                listInstances.SelectedIndex = -1;
                updateImage();
            }

            if (listActors.SelectedItem != null && listInstances.SelectedItem == null)
                pictureBox.Cursor = new Cursor(new Bitmap(((Actor)listActors.SelectedItem).actors[0]).GetHicon());
            else
                pictureBox.Cursor = Cursors.Default;
        }

        private void pictureBox_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (listActors.SelectedItem != null && listInstances.SelectedItem == null)
            {
                Instance newInstance = new Instance((Actor)listActors.SelectedItem);

                if (newInstance != null)
                {
                    listInstances.Items.Add(newInstance);
                    newInstance.x = e.X;
                    newInstance.y = background.Height - 1 - e.Y;
                    
                    saved = false;
                    updateImage();
                }                
            }
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control)
            {
                waypointing = true;
            }
            else if (e.KeyCode == Keys.Delete)
            {
                if (listInstances.SelectedItem != null)
                {
                    int selectedIndex = listInstances.SelectedIndex;
                    deleteSelectedInstanceToolStripMenuItem_Click(sender, e);
                 
                    if (listInstances.Items.Count <= selectedIndex)
                        listInstances.SelectedIndex = listInstances.Items.Count - 1;
                    else
                        listInstances.SelectedIndex = selectedIndex;
                }
            }
        }

        private void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            if (!e.Control)
            {
                waypointing = false;
                currentWaypoints.Clear();
            }
        }

        private void pictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (background == null || listInstances.SelectedItem != null)
                return;

            if (listActors.SelectedItem != null)
            {
                potential = null;
                updateImage();
                return;
            }

            foreach (Instance instance in listInstances.Items)
            {
                if ((e.X - instance.x) * (e.X - instance.x) + ((background.Height - 1 - e.Y) - instance.y) * ((background.Height - 1 - e.Y) - instance.y) < instance.tolerance)
                {
                    if (potential != instance)
                    {
                        potential = instance;
                        updateImage();
                    }
                    return;
                }
            }

            potential = null;
            updateImage();
        }

        private void levelBriefingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form form = new Form();
            Label label = new Label();
            TextBox textBox = new TextBox();
            Button buttonOk = new Button();
            Button buttonCancel = new Button();
            Int32 lines = levelBrief.Length - levelBrief.Replace("\\n", "n").Length + 1;

            form.Text = "Level Briefing";


            label.Text = levelBrief.Replace("\\n", "\r\n");
            textBox.Text = levelBrief;

            buttonOk.Text = "OK";
            buttonCancel.Text = "Cancel";
            buttonOk.DialogResult = DialogResult.OK;
            buttonCancel.DialogResult = DialogResult.Cancel;

            label.SetBounds(9, 20, 372, 13);
            textBox.SetBounds(12, 25 + 13 * lines, 372, 20);
            buttonOk.SetBounds(228, 60 + 13 * lines, 75, 23);
            buttonCancel.SetBounds(309, 60 + 13 * lines, 75, 23);

            label.AutoSize = true;
            textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
            buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

            form.ClientSize = new Size(396, 94 + 13 * lines);
            form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel });
            form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.StartPosition = FormStartPosition.CenterScreen;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.AcceptButton = buttonOk;
            form.CancelButton = buttonCancel;

            DialogResult dialogResult = form.ShowDialog();
            if (dialogResult == DialogResult.OK && levelBrief != textBox.Text)
            {
                saved = false;
                levelBrief = textBox.Text;
            }
        }
    }
}

